#include <stdlib.h>
#include "rarray.h"

static rarray_context_t *create_context(void)
{
	rarray_context_t *result = malloc(sizeof(rarray_context_t));

	result->size = 256;
	result->count = 0;
	result->bucket = malloc(sizeof(void *) * result->size);
	return result;
}

static void release_context(rarray_context_t *context)
{
	free(context->bucket);
	free(context);
}

void rarray_ref(rarray_t *self)
{
	if (self)
		self->ref++;
}

void rarray_unref(rarray_t *self)
{
	if (self && --(self->ref) == 0)
	{
		rarray_clear(self);
		release_context(self->context);
	}
}

void rarray_create(rarray_t *self, rarray_free_fn_t destructor)
{
	self->ref = 1;
	self->context = create_context();
	self->destructor = destructor;
}

void rarray_clear(rarray_t *self)
{
	if (self->destructor)
		for (int i = 0; i < self->context->count; i++)
			self->destructor(self->context->bucket[i]);

	self->context->count = 0;
}

void rarray_append(rarray_t *self, void *value)
{
	if (self->context->count + 1 > self->context->size)
	{
		self->context->size *= 2;
		self->context->bucket = realloc(self->context->bucket, sizeof(void *) * self->context->size);
	}

	self->context->bucket[self->context->count++] = value;
}

void rarray_foreach(rarray_t *self, rarray_walk_fn_t fn, void *context)
{
	for (int i = 0; i < self->context->count; i++)
		fn(self, self->context->bucket[i], context);
}

void rarray_save_context(rarray_t *self, rarray_context_t **context)
{
	*context = self->context;
	self->context = create_context();
}

void rarray_restore_context(rarray_t *self, rarray_context_t **context)
{
	rarray_clear(self);
	release_context(self->context);
	self->context = *context;
	*context = NULL;
}
